1、首先看一下网络模型
![](https://img-blog.csdnimg.cn/20200915085946927.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FZc2QzMg==,size_16,color_FFFFFF,t_70)
UDP协议是无连接,尽最大可能交付报文,没有拥塞控制,面向报文(不分割、不合并)
![](https://img-blog.csdnimg.cn/20190804110752399.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xpa2V3aW5kMTk5Mw==,size_16,color_FFFFFF,t_70)
TCP面向连接,提供可靠交付,有流量控制、拥塞控制,面向字节流(从上层传下的数据进行分割,分割成合适运输的数据块)只能是一对一连接。
![](https://img-blog.csdnimg.cn/20190804110806511.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xpa2V3aW5kMTk5Mw==,size_16,color_FFFFFF,t_70)
2、三菱的PLC通信
在三菱的PLC通信的MC协议中,分为串行通信的报文和以太网接口的报文。 在串口通信中,共有以下几种帧,其中1C,2C,3C帧支持格式1,2,3,4,在C帧里支持格式5通信
4C帧,QnA系列串行通信模块专用协议(Qna扩展帧)3C帧,QnA系列串行通信模块专用协议(Qna帧)2C帧,QnA系列串行通信模块专用协议(Qna简易帧)1C帧,A系列计算机链接模块专用协议
在以太网通信中,共有以下几种帧,每种帧支持二进制和ASCII格式。A-1E为较早的通信版本,对地址的操作范围有限(数据寄存器区的D0~D6143、D9000~D9255),Qna-3E可访问D0~D12287数据
4E帧,是3E帧上附加了“序列号”。3E帧,QnA系列以太网接口模块的报文格式,兼容SLMP的报文格式1E帧,A系列以太网接口模块的报文格式
Demo利用MC协议的A-1E模式,使用ASCII进行通信,基本实现int、float、bit的单点及批量的读写测。试,及利用异步监视PLC某点值的变化,使用PLC 的脉冲模拟数据的变化。代码编写未使用OOP思想,后期需要进行代码的优化
1、MC协议帧,A-1E帧
![](https://img-blog.csdnimg.cn/20200915085435962.png)
![](https://img-blog.csdnimg.cn/20200916174058843.png)
![](https://img-blog.csdnimg.cn/20200916174119212.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FZc2QzMg==,size_16,color_FFFFFF,t_70)
![](https://img-blog.csdnimg.cn/20200916174139858.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FZc2QzMg==,size_16,color_FFFFFF,t_70)
1、读还是写,字还是位
![](https://img-blog.csdnimg.cn/20201026080859229.png)
![](https://img-blog.csdnimg.cn/20201026080910126.png)
![](https://img-blog.csdnimg.cn/20200916173827654.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FZc2QzMg==,size_16,color_FFFFFF,t_70)
![](https://img-blog.csdnimg.cn/20200916173948531.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FZc2QzMg==,size_16,color_FFFFFF,t_70)
![](https://img-blog.csdnimg.cn/20200923111318709.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FZc2QzMg==,size_16,color_FFFFFF,t_70)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net.Sockets;
using Microsoft.VisualBasic;
using Microsoft.CodeAnalysis.VisualBasic;
using System.Threading;
namespace MCFx
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
//A-1E只能操作D0~D6143,D9000~D9255
groupBox1.Enabled = false;
}
private static TcpClient Client;
private string IpAddress;
private int PortNum;
private static byte[] Buffer; //=new byte[256];
private byte[] InBuff = new byte[1532];
private static string TxCommand;
private static string RxResponse;
private static string Temp;
private static int j;
double[] Dreg = new double[65536];
//private double[] Dreg;
private string DregStr;
private string SubHeader;
private int Muloffset;
//PLC连接
private void ConPlc(string IpAddress, int PortNum)
{
IpAddress = IpAddress;
PortNum = PortNum;
Client = new TcpClient();
try
{
Client.Connect(IpAddress, PortNum);
if (Client.Connected == true)
{
groupBox1.Enabled = true;
txtError.Text = " Success Connection";
}
else { MessageBox.Show("Connection Fail"); }
}
catch (Exception ex)
{
MessageBox.Show("Connection Fail,Next return code will be reback:{0}", ex.Message);
}
}
//PLC断开连接
private void DisconPlc()
{
try
{
if (Client == null) { MessageBox.Show("Not Connection PLC "); txtError.Text = "Not Connection PLC "; }
else
{
Client.GetStream().Close();
Client.Close();
if (Client.Connected == false)
{
txtError.Text = "Success DisConnection PLC";
}
groupBox1.Enabled = false;
}
}
catch (Exception e)
{
MessageBox.Show("Not Connection PLC ");
}
}
private bool DataQuery(string offset, string num)
{
if (offset == "")
{
MessageBox.Show("Please input your offset");
return false;
}
else if (num == "")
{
MessageBox.Show("Please input your ElementNum");
return false;
}
else { return true; }
}
//连接PLC
private void button7_Click(object sender, EventArgs e)
{
string IpAddress = txtIP.Text;
int PortNum = int.Parse(txtPort.Text);
ConPlc(IpAddress, PortNum);
}
//整型批量读 D区
private void button1_Click(object sender, EventArgs e)
{
double[] DregInt = new double[25536];
//使用A互换1E结构的命令,读出D0~D4(5个点)
TxCommand = "01 FF 000A 4420 00000000 05 00"; //二进制通信,以字为单位成批读出
// 读字单位 PC号 ASCii 起始地址 个数
TxCommand = TxCommand.Replace(" ", "");
if (DataQuery(txtoffset.Text, txtFloatNum.Text) == true)
{
//读取int个数处理
int num = int.Parse(txtFloatNum.Text);
//string HexNum = '0' + (num * 2).ToString();
string HexNum = string.Format("{0:X}", num); //大写对大写X x //122
HexNum = HexNum.ToString().PadLeft(2, '0'); //不够两个左边补0
TxCommand = TxCommand.Remove(20, 2);
TxCommand = TxCommand.Insert(20, HexNum);
//偏移量处理。比如从D1开始读
int offset = int.Parse(txtoffset.Text);
string OffsetNum = string.Format("{0:X}", offset); //大写对大写X x //122
OffsetNum = OffsetNum.ToString().PadLeft(2, '0'); //不够两个左边补0
TxCommand = TxCommand.Remove(18, 2);
TxCommand = TxCommand.Insert(18, OffsetNum);
Buffer = System.Text.Encoding.Default.GetBytes(TxCommand.Trim().ToCharArray());
//发送命令
Client.GetStream().Write(Buffer, 0, Buffer.Length);
//等待以太网适配器的响应
while (!Client.GetStream().DataAvailable)
{
Application.DoEvents();
}
Client.GetStream().Read(InBuff, 0, InBuff.Length);
RxResponse = System.Text.Encoding.Default.GetString(InBuff);
SubHeader = RxResponse.Substring(2, 2);//开始的第三位取两个
if (SubHeader == "00") //正常响应
{
//整型的16位批量处理
Temp = ""; //初始化输出字符
for (j = 0; j |